package com.jtpay.ysfproductionprocess.http;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import com.google.gson.JsonObject;
import com.jtpay.ysfproductionprocess.R;
import com.jtpay.ysfproductionprocess.enums.LogLevelEnum;
import com.jtpay.ysfproductionprocess.enums.LogModuleEnum;
import com.jtpay.ysfproductionprocess.http.dataStructure.BasicResponse;
import com.jtpay.ysfproductionprocess.http.dataStructure.JsonParams;
import com.jtpay.ysfproductionprocess.http.listener.TransApiResultListener;
import com.jtpay.ysfproductionprocess.http.loader.ApiLoader;
import com.jtpay.ysfproductionprocess.http.retrofit.RetrofitBasicResponseObserver;
import com.jtpay.ysfproductionprocess.http.retrofit.RetrofitObserver;
import com.jtpay.ysfproductionprocess.http.retrofit.RetrofitObserverAndListener;
import com.jtpay.ysfproductionprocess.model.CryptModel;
import com.jtpay.ysfproductionprocess.model.RemoteTaskModel;
import com.jtpay.ysfproductionprocess.utils.AlarmSoundManager;
import com.jtpay.ysfproductionprocess.utils.ApiConstant;
import com.jtpay.ysfproductionprocess.utils.LogUtil;
import com.jtpay.ysfproductionprocess.utils.SharedPreferenceUtil;
import com.jtpay.ysfproductionprocess.utils.manager.ToastUtil;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import static com.jtpay.ysfproductionprocess.http.ApiHelper.ApiStatusEnum.GET_TASK_API;
import static com.jtpay.ysfproductionprocess.utils.ApiConstant.*;
import static com.jtpay.ysfproductionprocess.utils.PayContext.*;


public class ApiHelper {
    private Context mContext;
    private ApiLoader mApiLoader;
    private ApiLoader mUploadLogApiLoader;

    private JsonParams params;
    private ApiStatusEnum statusEnum = ApiStatusEnum.ORI_API;
    private RetrofitObserverAndListener<BasicResponse<String>, RemoteTaskModel> taskApiServer;
    private SharedPreferenceUtil sharedPreferenceUtil = new SharedPreferenceUtil();

    public enum ApiStatusEnum {
        ORI_API,
        GET_TASK_API,
        //Header and encrypt message
        EN_QR_INFO,
        STORAGE_QR_INFO,
        EN_ORDER_ID,
        SET_DECRYPT_CONTENT,
        GET_SERVER_ADDRESS,
    }

    private static class Holder {
        @SuppressLint("StaticFieldLeak")
        private static final ApiHelper mHelper = new ApiHelper();
    }

    public Context getContext() {
        return mContext;
    }

    private void setContext(Context context) {
        if (context != null) {
            mContext = context;
        }
    }

    private ApiLoader getApiLoader() {
        if (mApiLoader == null) {
            mApiLoader = new ApiLoader(ApiConstant.getUrl());
        }
        return mApiLoader;
    }

    private ApiLoader getUploadLogApiLoader() {
        if (mUploadLogApiLoader == null) {
            mUploadLogApiLoader = new ApiLoader(DEBUG_SERVER_UPLOAD_LOG_ADDRESS_DEF, ApiConstant.DEFAULT_TIMEOUT, null);
        }
        return mUploadLogApiLoader;
    }

    public static ApiHelper getInstance(Context context) {
        Holder.mHelper.setContext(context);
        return Holder.mHelper;
    }

    public ApiStatusEnum getStatusEnum() {
        return statusEnum;
    }

    public void setStatusEnum(ApiStatusEnum apiStatusEnum) {
        statusEnum = apiStatusEnum;
    }

    private RetrofitObserverAndListener<BasicResponse<String>, RemoteTaskModel> getTaskApiServer() {
        if (taskApiServer == null) {
            taskApiServer = new RetrofitObserverAndListener<BasicResponse<String>, RemoteTaskModel>() {
                @Override
                public void onSuccess(BasicResponse<String> response) {
                    super.onSuccess(response);
                    try {
                        RemoteTaskModel taskModel = new RemoteTaskModel();
                        JSONObject jsonObject = new JSONObject(response.getData());
                        taskModel.setTaskType(jsonObject.optInt("taskType"));
                        JSONObject object = new JSONObject(
                                jsonObject.optString("taskContent"));
                        taskModel.setMoney(object.optString("money"));
                        taskModel.setReason(object.optString("reason"));
                        taskModel.setUnionPayOrderId(object.optString("unionPayOrderId"));
                        taskModel.setEn_content(object.optString("encryptContent"));
                        taskModel.setTime(object.optString("Time"));
                        taskApiServer.getListener().trans(taskModel);
                    } catch (Exception e) {
                        e.printStackTrace();
                        onError(e);
                    }
                }

                @Override
                public void onFail(BasicResponse<String> response) {
                    super.onFail(response);
                    sendLogMsg("new task onFail");
                    LogUtil.logUpload(mContext, "new task onFail", LogModuleEnum.GET_TASK_API.message, LogLevelEnum.LOG_ERROR.message);
                    getTaskAPI(taskApiServer.getListener());
                }

                @Override
                public void onError(Throwable e) {
                    super.onError(e);
                    if (!needLimited()) {
                        sendLogMsg("new task onError");
                        LogUtil.logUpload(mContext, "new task onError", LogModuleEnum.GET_TASK_API.message, LogLevelEnum.LOG_ERROR.message);
                        getTaskAPI(taskApiServer.getListener());
                    } else {
                        AlarmSoundManager.getInstance().play();
                        sendLogMsg(mContext.getString(R.string.api_error_count_max_tips));
                        LogUtil.logUpload(mContext, mContext.getString(R.string.api_error_count_max_tips), LogModuleEnum.GET_HEADER.message, LogLevelEnum.LOG_ERROR.message);

                    }
                }
            };
        }
        return taskApiServer;
    }

    private JsonParams getNewParams() {
        if (params == null) {
            params = new JsonParams();
            return params;
        }
        params.clear();
        return params;
    }

    /**
     * @param listener TransApiResultListener
     */
    public void getTaskAPI(final TransApiResultListener<RemoteTaskModel> listener) {
        setStatusEnum(GET_TASK_API);
        getTaskApiServer().setListener(listener);
        if (AlarmSoundManager.getInstance().isPlaying()) {
            AlarmSoundManager.getInstance().stop();
        }
        getApiLoader().postStrObserveObject(ApiConstant.GET_TASK_API, getNewParams().getEncodeObject())
                .subscribe(getTaskApiServer());
    }

    /**
     * @param encryptModel EncryptModel
     * @param listener     TransApiResultListener
     */
    public void getEncryptQrInfoAPI(final CryptModel encryptModel, final TransApiResultListener<CryptModel> listener) {
        setStatusEnum(ApiStatusEnum.EN_QR_INFO);
        params = getNewParams();
        params.put("getUrl", encryptModel.getEn_cryptModel().getCombinationUrl());
        params.put("money", encryptModel.getMoney());
        params.put("reason", encryptModel.getRemark());
        params.put("header", encryptModel.getEn_headerModel().getCombinationHeader());
        params.put("virtualCard", encryptModel.getEn_cryptModel().getEn_virtualCardNo());
        params.put("cityCode", encryptModel.getEn_cryptModel().getEn_cityCode());
        getApiLoader().postJsonObserveObject(ApiConstant.GET_ENCRYPT_QR_INFO, params.getEncodeObject())
                .subscribe(new RetrofitObserver<BasicResponse<JsonObject>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<JsonObject> response) {
                        super.onSuccess(response);
                        if (response.getData() == null) {
                            Intent intent = new Intent(ACTION_CONTINUE_TASK);
                            LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
                            return;
                        }
                        JsonObject jsonObject = response.getData();
                        encryptModel.setQr_content(jsonObject.get("encryptContent").getAsString());
                        encryptModel.setMoney(jsonObject.get("money").getAsString());
                        encryptModel.setRemark(jsonObject.get("reason").getAsString());
                        listener.trans(encryptModel);
                    }

                    @Override
                    public void onFail(BasicResponse<JsonObject> response) {
                        super.onFail(response);
                        LogUtil.logUpload(mContext, "getEncryptQrInfoAPI onFail = " + response.toString(), LogModuleEnum.ENCRYPT_QR_INFO.message, LogLevelEnum.LOG_ERROR.message);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        LogUtil.logUpload(mContext, "getEncryptQrInfoAPI onError = " + e.getMessage(), LogModuleEnum.ENCRYPT_QR_INFO.message, LogLevelEnum.LOG_ERROR.message);

                    }
                });
    }

    /**
     * @param encryptModel EncryptModel
     * @param listener     TransApiResultListener
     */
    public void storageQrInfoAPI(final CryptModel encryptModel, final TransApiResultListener<String> listener) {
        setStatusEnum(ApiStatusEnum.STORAGE_QR_INFO);
        params = getNewParams();
        params.put("money", encryptModel.getMoney());
        params.put("reason", encryptModel.getRemark());
        params.put("content", encryptModel.getDe_qr_content());
        getApiLoader().postStrObserveObject(ApiConstant.STORAGE_QR_INFO, params.getEncodeObject())
                .subscribe(new RetrofitObserver<BasicResponse<String>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<String> response) {
                        super.onSuccess(response);
                        listener.trans("success");
                    }

                    @Override
                    public void onFail(BasicResponse<String> response) {
                        super.onFail(response);
                        LogUtil.logUpload(mContext, "storageQrInfoAPI onFail = " + response.toString(), LogModuleEnum.STORAGE_QR_INFO.message, LogLevelEnum.LOG_ERROR.message);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        LogUtil.logUpload(mContext, "storageQrInfoAPI onError " + e.getMessage(), LogModuleEnum.STORAGE_QR_INFO.message, LogLevelEnum.LOG_ERROR.message);
                    }
                });
    }

    /**
     * @param encryptModel EncryptModel
     * @param listener     TransApiResultListener
     */
    public void setOrderIdAPI(final CryptModel encryptModel, final TransApiResultListener<String> listener) {
        setStatusEnum(ApiStatusEnum.EN_ORDER_ID);
        params = getNewParams();
        params.put("unionPayOrderId", encryptModel.getOrderId());
        params.put("encryptUnionPayOrderId", encryptModel.getEn_orderId());
        params.put("header", encryptModel.getEn_headerModel().getCombinationHeader());
        getApiLoader().postStrObserveObject(ApiConstant.SET_ORDER_ID, params.getEncodeObject())
                .subscribe(new RetrofitObserver<BasicResponse<String>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<String> response) {
                        super.onSuccess(response);
                        listener.trans("success");
                    }

                    @Override
                    public void onFail(BasicResponse<String> response) {
                        super.onFail(response);
                        LogUtil.logUpload(mContext, "setOrderIdAPI onFail " + response.toString(), LogModuleEnum.SET_ORDER_ID.message, LogLevelEnum.LOG_ERROR.message);

                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        LogUtil.logUpload(mContext, "setOrderIdAPI onError " + e.getMessage(), LogModuleEnum.SET_ORDER_ID.message, LogLevelEnum.LOG_ERROR.message);

                    }
                });
    }

    /**
     * @param encryptModel EncryptModel
     * @param listener     TransApiResultListener
     */
    public void setDecryptContentAPI(final CryptModel encryptModel, final TransApiResultListener<String> listener) {
        setStatusEnum(ApiStatusEnum.SET_DECRYPT_CONTENT);
        params = getNewParams();
        params.put("unionPayOrderId", encryptModel.getOrderId());
        params.put("encryptContent", encryptModel.getEn_content());
        params.put("decryptContent", encryptModel.getDe_content());
        getApiLoader().postStrObserveObject(ApiConstant.SET_DECRYPT_CONTENT, params.getEncodeObject())
                .subscribe(new RetrofitObserver<BasicResponse<String>>(mContext) {
                    @Override
                    public void onSuccess(BasicResponse<String> response) {
                        super.onSuccess(response);
                        listener.trans("success");
                    }

                    @Override
                    public void onFail(BasicResponse<String> response) {
                        super.onFail(response);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                    }
                });
    }

    /**
     * @param shopCode   shopCode
     * @param ysfAccount ysfAccount
     * @param listener   TransApiResultListener
     */
    public void getServerAPI(final String shopCode, final String ysfAccount,
                             final TransApiResultListener<String> listener) {
        setStatusEnum(ApiStatusEnum.GET_SERVER_ADDRESS);
        mApiLoader = null;
        params = getNewParams();
        params.put("mercantNo", shopCode);
        params.put("account", ysfAccount);
        params.put("accountType", PAYMENT);
        new ApiLoader(getGetServerAddressApi()).postStrObserveObject(
                GET_SERVER_ADDRESS_API, params.getEncodeObject())
                .subscribe(new RetrofitObserverAndListener<BasicResponse<String>, String>() {
                    @Override
                    public void onSuccess(BasicResponse<String> response) {
                        super.onSuccess(response);
                        try {
                            JSONObject jsonObject = new JSONObject(response.getData());
                            LogUtil.log("getServerAPI  " + response.getData());
                            String ip = jsonObject.getString("ip");
                            String systemCode = jsonObject.getString("systemCode");
                            sharedPreferenceUtil.SP_SAVE(mContext, SP_SHOP_SYSTEMCODE_KEY, systemCode);
                            ApiConstant.URL_IP = ip;
                            listener.trans(ip);
                        } catch (JSONException e) {
                            e.printStackTrace();
                            sendLogMsg("getServerAddress error " + e.getMessage());
                        }
                    }

                    @Override
                    public void onFail(BasicResponse<String> response) {
                        super.onFail(response);
                        sendLogMsg("getServerAPI onFail " + response.toString());
                        LogUtil.logUpload(mContext, "getServerAPI onFail " + response.toString(), LogModuleEnum.GET_SERVER_ADDRESS.message, LogLevelEnum.LOG_ERROR.message);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        sendLogMsg("getServerAPI onError " + e.getMessage());
                        LogUtil.logUpload(mContext, "getServerAPI onError " + e.toString(), LogModuleEnum.GET_SERVER_ADDRESS.message, LogLevelEnum.LOG_ERROR.message);

                    }
                });
    }

    public void singleLogUploadAPI(String id, String moduleLog, String logLevel, String logContent, String payType) {
        params = getNewParams();
        params.put("systemCoding", sharedPreferenceUtil.SP_READ(mContext, SP_SHOP_SYSTEMCODE_KEY));
        params.put("logType", "2");
        params.put("logBelongs", id);
        params.put("moduleLog", moduleLog);
        params.put("logLevel", logLevel);
        params.put("logContent", logContent);
        params.put("productType", "yunshanfu");
        params.put("payType", payType);
        getUploadLogApiLoader().postJsonObserveJsonParam(ApiConstant.UPLOAD_LOG_API, params)
                .subscribe(new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>() {
                    @Override
                    public void onSuccess(BasicResponse<JsonObject> response) {
                        super.onSuccess(response);
                    }

                    @Override
                    public void onFail(BasicResponse<JsonObject> response) {
                        super.onFail(response);
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                    }
                });
    }


    public void fileUploadAPI(String id, String payType, final String filePath, String fileName, final TransApiResultListener<String> listener) {
        final JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("systemCoding", sharedPreferenceUtil.SP_READ(mContext, SP_SHOP_SYSTEMCODE_KEY));
            jsonObject.put("logType", "2");
            jsonObject.put("logBelongs", id);
            jsonObject.put("payType", payType);
            jsonObject.put("fileName", fileName);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        params = getNewParams();
        params.setUploadFilePath(filePath);
        new ApiLoader(DEBUG_SERVER_UPLOAD_LOG_ADDRESS_DEF, DEFAULT_FILE_UPLOAD_TIMEOUT, new Interceptor() {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Request original = chain.request();
                // Request customization: add request headers
                Request.Builder requestBuilder = original.newBuilder()
                        .addHeader("wolegequ", String.valueOf(jsonObject));
                Request request = requestBuilder.build();
                return chain.proceed(request);
            }
        }).postJsonObserveJsonParamUpload(ApiConstant.UPLOAD_LOG_FILE_API, params)
                .subscribe(new RetrofitBasicResponseObserver<BasicResponse<JsonObject>>() {
                    @Override
                    public void onSuccess(BasicResponse<JsonObject> response) {
                        super.onSuccess(response);
                        listener.trans(filePath);
                    }

                    @Override
                    public void onFail(BasicResponse<JsonObject> response) {
                        super.onFail(response);
                        ToastUtil.showShort(mContext.getString(R.string.log_upload_fail));
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        ToastUtil.showShort(mContext.getString(R.string.log_upload_fail));
                    }
                });
    }

    /**
     * @param content send log content
     */
    private void sendLogMsg(String content) {
        Intent intent = new Intent(ACTION_UNION_PAY_SHOW_LOG);
        intent.putExtra(BROADCAST_CONTENT_KEY, content);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }
}
